Skip to content

Feature: fix/audit-hardening to dev - #447

Merged
aamoghS merged 6 commits into
devfrom
fix/audit-hardening
Oct 1, 2026
Merged

aamoghS merged 6 commits into
devfrom
fix/audit-hardening

Conversation

@github-actions

@github-actions github-actions Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

fix: second audit pass on judging, admins, terms and teams

  • Withdrawing a project drops its unscored queue slots, and the judge
    page moves on to the next table when the slot on screen is gone.
  • assignToHackathon no longer queues a project twice; isJudge rejects a
    malformed id as 400 instead of a Postgres 500; judge min/max per judge
    must be whole numbers with max >= min.
  • The last-super-admin guard also covers deactivation and ending the
    term, and no longer counts expired super admins.
  • Terms and semester ends are computed in Eastern time. The last six
    hours of a semester count as the next one, so renewing a membership
    stored on the old UTC boundary still buys a full semester.
  • leaveTeam and disbandTeam lock the team row, serialising with joins.
  • Chunk-error recovery reloads again after a later deploy; ModalWrapper
    no longer steals focus when its onClose changes; Hacklytics anchors
    drop content-visibility so nav taps land on the section.

fix: close remaining audit gaps in submissions, waves and metrics

  • hackathon_projects gets withdrawn_by_admin_at (additive). An organiser
    pulling a project before judging left no judging row, so the team
    could resubmit it straight back into the gallery; submitProject now
    refuses on the column too.
  • submitProject bounds name, description and list sizes, and keeps only
    tracks and challenges the hackathon offers. Unknown values are dropped
    rather than refused: the form cannot untick a track removed since.
  • acceptWave locks the hackathon row, so two concurrent waves get
    different numbers instead of both claiming max + 1.
  • The metrics term label reads Eastern time, matching currentTerm.

Note

Medium Risk
Changes touch membership billing boundaries, admin privilege invariants, and judging queue deletion during live events—high-impact domains, though mostly defensive guards and additive schema.

Overview
This PR closes several audit gaps around organiser project withdrawal, admin lockout, membership terms, and race-prone team/wave flows, plus small UX and resilience fixes on the web apps.

Judging and withdrawals: When an organiser pulls a project, the API now stamps withdrawnByAdminAt, marks the judging entry withdrawn, and deletes unscored judgeQueue rows so judges are not routed to dead tables. Teams cannot resubmit after an organiser pull (column + legacy judging-row check). The judge portal auto-advances when complete/skip/force-skip hits a withdrawn slot. Judge assignment skips projects already queued and appends with correct order; isJudge rejects malformed UUIDs as 400 before Postgres; bulk assign validates max ≥ min and integer min/max.

Super admins: The “last super admin” guard now blocks demotion, deactivation, and setting an already-ended term, counting only non-expired active super admins.

Terms and metrics: currentTerm, semesterEndDate, and the metrics term label use America/New_York; the last six hours of a semester roll to the next term so renewals (including memberships stored on old UTC boundaries) buy a full semester.

Concurrency and validation: acceptWave locks the hackathon row for wave numbering; leaveTeam / disbandTeam lock the team row. submitProject adds field length caps and silently filters tracks/challenges to what the hackathon offers.

Frontend: Chunk reload recovery uses a 30s timestamp instead of a one-shot flag; ModalWrapper stops re-running focus trap when onClose identity changes; Hacklytics drops content-visibility on section anchors so hash nav lands correctly.

Reviewed by Cursor Bugbot for commit 0711699. Bugbot is set up for automated code reviews on this repo. Configure here.

aamoghS and others added 4 commits September 29, 2026 15:43
- Withdrawing a project drops its unscored queue slots, and the judge
  page moves on to the next table when the slot on screen is gone.
- assignToHackathon no longer queues a project twice; isJudge rejects a
  malformed id as 400 instead of a Postgres 500; judge min/max per judge
  must be whole numbers with max >= min.
- The last-super-admin guard also covers deactivation and ending the
  term, and no longer counts expired super admins.
- Terms and semester ends are computed in Eastern time. The last six
  hours of a semester count as the next one, so renewing a membership
  stored on the old UTC boundary still buys a full semester.
- leaveTeam and disbandTeam lock the team row, serialising with joins.
- Chunk-error recovery reloads again after a later deploy; ModalWrapper
  no longer steals focus when its onClose changes; Hacklytics anchors
  drop content-visibility so nav taps land on the section.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 3f7d4aa. Configure here.

Comment thread sites/mainweb/app/(portal)/hackathons/[id]/judge/page.tsx
- hackathon_projects gets withdrawn_by_admin_at (additive). An organiser
  pulling a project before judging left no judging row, so the team
  could resubmit it straight back into the gallery; submitProject now
  refuses on the column too.
- submitProject bounds name, description and list sizes, and keeps only
  tracks and challenges the hackathon offers. Unknown values are dropped
  rather than refused: the form cannot untick a track removed since.
- acceptWave locks the hackathon row, so two concurrent waves get
  different numbers instead of both claiming max + 1.
- The metrics term label reads Eastern time, matching currentTerm.
@github-actions github-actions Bot added the bug Something isn't working label Sep 30, 2026
@github-actions

Copy link
Copy Markdown
Contributor Author

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@github-actions

github-actions Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor Author

Visit the preview URL for this PR (updated for commit 0711699):

https://hacklytics2027--pr-447-dfcx53hd.web.app

(expires Thu, 08 Oct 2026 15:15:45 GMT)

🔥 via Firebase Hosting GitHub Action 🌎

Sign: c48ba34db61581e25fe2978355160b5eefe0e83f

A failed getNextTable refetch still resolves with the cached answer,
which is the withdrawn table itself, so a network blip put the judge
back on the dead card under a message saying they had a new one. An
error result, or one naming the same slot, now reports the failure;
pressing any card action again retries.
@aamoghS
aamoghS merged commit 5bfe9b3 into dev Oct 1, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⤵️ pull bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant